package com.huangsm.juc.consumer;

import lombok.AllArgsConstructor;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用condition加重入锁解决虚假唤醒和实现消费者生产者案例
 */
public class TestProductorAndConsumerForLock {
    public static void main(String[] args) {
        Clerk1 clerk1=new Clerk1();
        Productor1 productor=new Productor1(clerk1);
        Consumer1 consumer=new Consumer1(clerk1);

        new Thread(productor,"生产者A").start();
        new Thread(consumer,"消费者A").start();
        //出现了虚假唤醒，如果想要解决这个问题，应该将wait总是使用在循环中
        new Thread(productor,"生产者B").start();
        new Thread(consumer,"消费者B").start();
    }
}
class Clerk1{
    private int product=0;
    Lock lock=new  ReentrantLock();
    private Condition condition=lock.newCondition();
    //进货
    public  void get(){
        lock.lock();
        try {
            while (product>=1){//为了避免出现虚假唤醒问题，wait应该总是出现了循环当中
                System.out.println("产品已满无法添加");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+":"+ ++product);
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }
    //卖货
    public  void sale(){
        lock.lock();
       try {
           while (product<=0){
               System.out.println("货买完啦");
               try {
                   condition.await();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
           System.out.println(Thread.currentThread().getName()+":"+ --product);
           condition.signalAll();
       }finally {
           lock.unlock();
       }

    }
}

//生产者
@AllArgsConstructor
class Productor1 implements Runnable{
    private Clerk1 clerk;

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.get();
        }
    }
}

//消费者
@AllArgsConstructor
class Consumer1 implements Runnable{
    private Clerk1 clerk;

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}

